package org.fitweb.runners;

import fit.Counts;
import fitnesse.trinidad.FitTestEngine;
import fitnesse.trinidad.TestRunner;
import org.apache.commons.lang.StringUtils;
import org.fitweb.ExtensionPoint;
import org.fitweb.files.DirectoryScrounger;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

import static org.fitweb.files.PathFinder.*;
import static org.junit.Assert.*;

public class SingleTestRunner {

    String relativeTestPath;
    String fileOutputPath;
    String inputRoot;
    static boolean directoriesSynchronised;
    private String outputRoot;
    private TestRunner runner;

    public SingleTestRunner(String inputRoot, String outputRoot, String testFilePath) {
        checkNotBlank(inputRoot, outputRoot, testFilePath);
        this.relativeTestPath = relativePath(inputRoot, testFilePath);
        this.outputRoot = outputRoot;
        this.fileOutputPath = nestedOutputPath(outputRoot, relativeTestPath);
        this.inputRoot = inputRoot;
        checkHtml(relativeTestPath);
        runner = testRunner(fileOutputPath);
    }

    private TestRunner testRunner(String outputPath) {
        try {
            return new TestRunner(new FitNotFitnesseRepository(), new FitTestEngine(), outputPath);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private String nestedOutputPath(String outputDirectoryPath, String relativeTestPath) {
        return new File(outputDirectoryPath, relativeTestPath).getParentFile().getPath();
    }

    @ExtensionPoint
    public void runSingleTest() throws IOException {
        // TODO - CAS - Nov 1, 2010 - Move synchronisation code into FitNotFitnesseRepository.prepareResultRepository()
        synchroniseTargetFromSource();
        Counts counts = runner.runTest(canonical(inputRoot, relativeTestPath));
        if ((counts.wrong + counts.exceptions) > 0) {
            System.err.println("===> FIT TEST FAILED: " + testName());
            File outputFile = new File(fileOutputPath, testName());
            System.err.println("===> RESULTS: " + outputFile.toURI().toURL());
            fail(testName() + " failed");
        }
    }

    private void synchroniseTargetFromSource() {
        if (!directoriesSynchronised) {
            System.out.println(" -- Synchronising directories --");
            new DirectoryScrounger().synchronise(inputRoot, outputRoot);
            directoriesSynchronised = true;
        }
    }

    String testName() {
        return relativeTestPath.replaceAll(".*(/|\\\\)", "");
    }

    private void checkNotBlank(String ... paths) {
        for (String path : paths) {
            if (StringUtils.isBlank(path)) {
                throw new IllegalArgumentException("None of the input paths can be blank. You provided: " + Arrays.asList(paths));
            }
        }
    }

    private void checkHtml(String testFile) {
        String path = canonical(testFile);
        boolean html = path.endsWith("html") || path.endsWith("HTML");
        if (!html) throw new IllegalArgumentException("The test file is not html: " + testFile);
    }
}